package ch.sv7.tool.dbmanager.db;

import java.io.Serializable;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import ch.sv7.tool.dbmanager.db.difference.ExtraTableDifference;
import ch.sv7.tool.dbmanager.db.difference.MissingTableDifference;
import ch.sv7.tool.dbmanager.db.difference.SchemaDifferences;

public class DatabaseSchema implements SchemaElement, Serializable, Cloneable {

	private static final long serialVersionUID = 1L;

	protected Map tables;

	public DatabaseSchema() {
		tables = new HashMap();
	}

	public Object clone() throws CloneNotSupportedException {
		return super.clone();
	}
	
	public TableSchema getTableSchema(String tableName) {
		TableSchema ts = (TableSchema) tables.get(tableName);
		return ts;
	}

	public String getSchemaIdentifier() {
		return "Database";
	}

	public void addTableSchema(TableSchema ts) {
		tables.put(ts.getName(), ts);
	}

	public Iterator iterator() {
		return tables.values().iterator();
	}

	public String[] getTableNames(){
		return (String[])tables.keySet().toArray(new String[tables.size()]);
	}
	
	public void removeForeignKeys() {
		Iterator iter = iterator();
		while (iter.hasNext()) {
			TableSchema ts = (TableSchema)iter.next();
			ts.getForeignKeys().clear();
			ts.getReferencedForeignKeys().clear();
		}		
		buildReferences();
	}
	
	public void buildReferences() {
		Iterator iter = iterator();
		while (iter.hasNext()) {
			TableSchema ts = (TableSchema)iter.next();
			ts.getReferencedForeignKeys().clear();
		}
		iter = iterator();
		while (iter.hasNext()) {
			TableSchema ts = (TableSchema)iter.next();
			ts.buildIndexReferences();
			ts.buildForeignKeysReferences(tables);
		}
	}
	
	public int size() {
		return tables.size();
	}

	public String toString() {
		return tables.toString();
	}
	
	public void computeDifferencesFromActual(SchemaDifferences diffs, DatabaseSchema actualSchema) {
		Iterator iter = iterator();
		while (iter.hasNext()) {
			TableSchema ts = (TableSchema)iter.next();
			TableSchema actualTs = actualSchema.getTableSchema(ts.name);
			if (actualTs == null) {
				diffs.addDifference(this, new MissingTableDifference(ts));
			} else {
				ts.computeDifferencesFromActual(diffs, actualTs);
			}
		}
		
		Iterator actualIter = actualSchema.iterator();
		while (actualIter.hasNext()) {
			TableSchema actualTs = (TableSchema)actualIter.next();
			TableSchema ts = getTableSchema(actualTs.getName());
			if (ts == null) {
				diffs.addDifference(this, new ExtraTableDifference(actualTs));
			}
		}
	}

	public void forceLowerCase() {
		Iterator iter = iterator();
		while (iter.hasNext()) {
			TableSchema ts = (TableSchema) iter.next();
			ts.forceLowerCase();
		}
	}

	public void forceUpperCase() {
		Iterator iter = iterator();
		while (iter.hasNext()) {
			TableSchema ts = (TableSchema) iter.next();
			ts.forceUpperCase();
		}
	}
}
